    /*-------------------------------- Arctic Core ------------------------------
 * Copyright (C) 2013, ArcCore AB, Sweden, www.arccore.com.
 * Contact: <contact@arccore.com>
 * 
 * You may ONLY use this file:
 * 1)if you have a valid commercial ArcCore license and then in accordance with  
 * the terms contained in the written license agreement between you and ArcCore, 
 * or alternatively
 * 2)if you follow the terms found in GNU General Public License version 2 as 
 * published by the Free Software Foundation and appearing in the file 
 * LICENSE.GPL included in the packaging of this file or here 
 * <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>
 *-------------------------------- Arctic Core -----------------------------*/

/*
 *  General requirements
 */

/* Disable MISRA 2004 rule 16.2, MISRA 2012 rule 17.2.
 * This because of recursive calls to readDidData.
 *  */
//lint -estring(974,*recursive*)

/** @req DCM273 */ /** @req DCM272 */
/** @req DCM039 */ /** @req DCM038 */ /** @req DCM269 */
/** @req DCM271 */ /** @req DCM274 */ /** @req DCM275 */
/** @req DCM007 */
#include <string.h>
#include "Dcm.h"
#include "Dcm_Internal.h"
#if defined(USE_DEM)
#include "Dem.h"
#else
#endif
//#include "MemMap.h"
#if defined(USE_MCU)
#include "Mcu.h"
#endif

/*
 * Macros
 */
#define ZERO_SUB_FUNCTION				0x00
#define DCM_FORMAT_LOW_MASK			0x0F
#define DCM_FORMAT_HIGH_MASK			0xF0
#define DCM_MEMORY_ADDRESS_MASK		0x00FFFFFF
#define DCM_DID_HIGH_MASK 				0xFF00			
#define DCM_DID_LOW_MASK				0xFF
#define DCM_PERODICDID_HIGH_MASK		0xF200
#define SID_AND_DDDID_LEN   0x4
#define SDI_AND_MS_LEN   0x4

#define SID_AND_SDI_LEN   0x6
#define SID_AND_PISDR_LEN   0x7

/* == Parser macros == */
/* General */
#define SID_INDEX 0
#define SID_LEN 1
#define SF_INDEX 1
#define SF_LEN 1
#define DTC_LEN 3
#define FF_REC_NUM_LEN 1
/* Read/WriteMemeoryByAddress */
#define ALFID_INDEX 1
#define ALFID_LEN 1
#define ADDR_START_INDEX 2
/* DynamicallyDefineDataByIdentifier */
#define DDDDI_INDEX 2
#define DDDDI_LEN 2
#define DYNDEF_ALFID_INDEX 4
#define DYNDEF_ADDRESS_START_INDEX 5
/* InputOutputControlByIdentifier */
#define IOI_INDEX 1
#define IOI_LEN 2
#define IOCP_INDEX 3
#define IOCP_LEN 1
#define COR_INDEX 4
/* CommunicationControl */
#define CC_CTP_INDEX 2
#define COMM_CTRL_ISO_RES_SF_LOW    0x04
#define COMM_CTRL_ISO_RES_SF_HIGH   0x3F
#define COMM_CTRL_ISO_RES_SF        0x7F
#define IS_IN_ISO_RESERVED_RANGE(_x)    ((_x >= COMM_CTRL_ISO_RES_SF_LOW) && (_x <= COMM_CTRL_ISO_RES_SF_HIGH))
#define IS_ISO_RESERVED(_x) (IS_IN_ISO_RESERVED_RANGE(_x) || (COMM_CTRL_ISO_RES_SF == _x))

#define BYTES_TO_DTC(hb, mb, lb)	(((uint32)(hb) << 16) | ((uint32)(mb) << 8) | (uint32)(lb))
#define DTC_HIGH_BYTE(dtc)			(((uint32)(dtc) >> 16) & 0xFFu)
#define DTC_MID_BYTE(dtc)			(((uint32)(dtc) >> 8) & 0xFFu)
#define DTC_LOW_BYTE(dtc)			((uint32)(dtc) & 0xFFu)

#define TIMER_DECREMENT(timer) \
        if (timer >= DCM_MAIN_FUNCTION_PERIOD_TIME_MS) { \
            timer = timer - DCM_MAIN_FUNCTION_PERIOD_TIME_MS; \
        } \

typedef enum {
	DCM_READ_MEMORY = 0,
	DCM_WRITE_MEMORY,
} DspMemoryServiceType;

typedef enum {
	DCM_DSP_RESET_NO_RESET,
	DCM_DSP_RESET_PENDING,
	DCM_DSP_RESET_WAIT_TX_CONF,
} DcmDspResetStateType;

typedef struct {
	DcmDspResetStateType resetPending;
	PduIdType resetPduId;
	PduInfoType *pduTxData;
	Dcm_EcuResetType resetType;
} DspUdsEcuResetDataType;

typedef struct {
	boolean sessionPending;
	PduIdType sessionPduId;
	Dcm_SesCtrlType session;
} DspUdsSessionControlDataType;

typedef enum {
	DCM_READ_DID_IDLE,
	DCM_READ_DID_PENDING_COND_CHECK,
	DCM_READ_DID_PENDING_READ_DATA
} ReadDidPendingStateType;

/* flash */
typedef enum {
    DCM_WRITE_FLASH_IDLE,
    DCM_WRITE_FLASH_PENDING,
} WriteFlashPendingStateType;

typedef struct {
	Dcm_ProtocolAddrTypeType addrType;
	uint8_t	 u32TimeCounter;
    WriteFlashPendingStateType stateTransferData;
	WriteFlashPendingStateType stateTransferDataExit;
    const PduInfoType* pduRxData;
    PduInfoType* pduTxData;
} DspUdsWriteFlashPendingType;


typedef enum {
    DCM_WRITE_DID_IDLE,
    DCM_WRITE_DID_PENDING,
} WriteDidPendingStateType;
typedef enum {
	DCM_ROUTINE_DID_IDLE,
	DCM_ROUTINE_DID_PENDING,
} RoutineDidPendingStateType;

typedef struct {
	ReadDidPendingStateType state;
	const PduInfoType* pduRxData;
	PduInfoType* pduTxData;
	uint16 txWritePos;
	uint16 nofReadDids;
	uint16 reqDidIndex;
	uint16 pendingDid;
	uint16 pendingDidLength;
} DspUdsReadDidPendingType;

typedef struct {
	Dcm_ProtocolAddrTypeType addrType;
    WriteDidPendingStateType state;
    const PduInfoType* pduRxData;
    PduInfoType* pduTxData;
} DspUdsWriteDidPendingType;
typedef struct {
	uint32	 u32TimeCounter;
	Dcm_ProtocolAddrTypeType addrType;
    RoutineDidPendingStateType state;
    const PduInfoType* pduRxData;
    PduInfoType* pduTxData;
} DspUdsRoutineDidPendingType;


static DspUdsEcuResetDataType dspUdsEcuResetData;
static DspUdsSessionControlDataType dspUdsSessionControlData;
static DspUdsReadDidPendingType dspUdsReadDidPending;
static DspUdsWriteDidPendingType dspUdsWriteDidPending;
static DspUdsRoutineDidPendingType dspUdsRoutineDidPending;
static DspUdsWriteFlashPendingType dspUdsWriteFlashPending;

typedef struct {
	boolean 						reqInProgress;
	Dcm_SecLevelType				reqSecLevel;
#if (DCM_SECURITY_EOL_INDEX != 0)
	DspUdsSecurityAccessChkParam    secFalseAttemptChk[DCM_SECURITY_EOL_INDEX];
    uint8                         currSecLevIdx; //Current index for secFalseAttemptChk
#endif
	const Dcm_DspSecurityRowType	*reqSecLevelRef;
} DspUdsSecurityAccessDataType;

static DspUdsSecurityAccessDataType dspUdsSecurityAccesData;

typedef enum{
	DCM_DDD_SOURCE_DEFAULT,
	DCM_DDD_SOURCE_DID,
	DCM_DDD_SOURCE_ADDRESS
}Dcm_DspDDDSourceKindType;

typedef struct{
	uint32 PDidTxCounter;
	uint32 PDidTxCounterLimit;
	uint8  PeriodicDid;
}Dcm_pDidType;/* a type to save  the periodic DID and cycle */

typedef struct{
	Dcm_pDidType dspPDid[DCM_LIMIT_NUMBER_PERIOD_DATA];	/*a buffer to save the periodic DID and cycle   */
	uint8 PDidNr;										/* note the number of periodic DID is used */
}Dsp_pDidRefType;

static Dsp_pDidRefType dspPDidRef;

#ifdef DCM_USE_SERVICE_INPUT_OUTPUT_CONTROL_BY_IDENTIFIER
#if 0 < DCM_DID_LIST_EOL_INDEX
#define DCM_USE_CONTROL_DIDS
typedef struct {
    uint16 did;
    boolean controlActive;
}Dcm_DspIOControlStateType;
static Dcm_DspIOControlStateType IOControlStateList[DCM_DID_LIST_EOL_INDEX];
#endif
#endif

//������ϴӲ����ظ���Ӧ��
uint8 FunctionalDiagnosticsNeverReturnedNegativeResponseCode_Table[FDNRNRCN]=  
{
	0x11, 0x7F, 0x12, 0X7E, 0x31
};

uint8 u8SecurityLevel1 = 0;

/*
 * * static Function
 */
static void DspCancelPendingDid(uint16 didNr, ReadDidPendingStateType pendingState, PduInfoType *pduTxData );

#ifdef DCM_USE_CONTROL_DIDS
static void DspStopInputOutputControl(boolean checkSessionAndSecLevel);
#endif
extern void Dcm_NotifyS3ServerTimeout(void);

void DspResetDiagnosticActivityOnSessionChange(Dcm_SesCtrlType newSession)
{
    //(void)newSession;
#ifdef DCM_USE_CONTROL_DIDS
    /* DCM628 says that active control should be stopped on transition
     * to default session only. But stop it if active control is not
     * supported in the new session (which should be the current session
     * as it is assumed that session is changed before calling this function) or
     * in the new security level. */
    DspStopInputOutputControl(TRUE);
#endif
	if(newSession == DCM_DEFAULT_SESSION)
	{
		Dcm_NotifyS3ServerTimeout();
	}
}

void DcmDspResetDiagnosticActivity(void)
{
#ifdef DCM_USE_CONTROL_DIDS
    DspStopInputOutputControl(FALSE);
#endif
}

void DspInit(boolean firstCall)
{
	dspUdsSecurityAccesData.reqInProgress = FALSE;
	dspUdsEcuResetData.resetPending = DCM_DSP_RESET_NO_RESET;
	dspUdsSessionControlData.sessionPending = FALSE;
	dspUdsSessionControlData.session = DCM_DEFAULT_SESSION;
	u8SecurityLevel1 = 0;
	/* clear periodic send buffer */
	memset(&dspPDidRef,0,sizeof(dspPDidRef));

	Dcm_E_CommunicationDefauitControl();

#ifdef DCM_USE_CONTROL_DIDS
	if(firstCall) {
	    memset(IOControlStateList, 0, sizeof(IOControlStateList));
	}
#endif
#if (DCM_SECURITY_EOL_INDEX != 0)
	uint8 temp = 0;
	if (firstCall) {
	    //Reset the security access attempts
	    do {
	        dspUdsSecurityAccesData.secFalseAttemptChk[temp].secAcssAttempts = 0;
	        if (Dcm_ConfigPtr->Dsp->DspSecurity->DspSecurityRow[temp].DspSecurityDelayTimeOnBoot >= DCM_MAIN_FUNCTION_PERIOD_TIME_MS) {
	            dspUdsSecurityAccesData.secFalseAttemptChk[temp].timerSecAcssAttempt = Dcm_ConfigPtr->Dsp->DspSecurity->DspSecurityRow[temp].DspSecurityDelayTimeOnBoot;
	            dspUdsSecurityAccesData.secFalseAttemptChk[temp].startDelayTimer = DELAY_TIMER_ON_EXCEEDING_LIMIT_ACTIVE;
	        }
	        else {
	            dspUdsSecurityAccesData.secFalseAttemptChk[temp].startDelayTimer = DELAY_TIMER_DEACTIVE;
	        }
	        temp++;
	    } while (temp < DCM_SECURITY_EOL_INDEX);
	}
#else
	(void)firstCall;
#endif
}

void DspResetMainFunction(void)
{
	if( DCM_DSP_RESET_PENDING == dspUdsEcuResetData.resetPending )
	{
		switch( DcmE_EcuReset(dspUdsEcuResetData.resetType) )
		{
		case E_OK:
			dspUdsEcuResetData.resetPending = DCM_DSP_RESET_WAIT_TX_CONF;
			// Create positive response
			dspUdsEcuResetData.pduTxData->SduDataPtr[1] = dspUdsEcuResetData.resetType;
			dspUdsEcuResetData.pduTxData->SduLength = 2;
			DsdDspProcessingDone(DCM_E_POSITIVERESPONSE);
			break;
		case E_PENDING:
			dspUdsEcuResetData.resetPending = DCM_DSP_RESET_PENDING;
			break;
		case E_NOT_OK:
		default:
			dspUdsEcuResetData.resetPending = DCM_DSP_RESET_NO_RESET;
			DsdDspProcessingDone(DCM_E_CONDITIONSNOTCORRECT);
			break;
		}
	}
}

void DspWriteFlashMainFunction(void) {
	if(dspUdsWriteFlashPending.u32TimeCounter > 0) dspUdsWriteFlashPending.u32TimeCounter--;
	if( (DCM_WRITE_FLASH_PENDING == dspUdsWriteFlashPending.stateTransferData) && (dspUdsWriteFlashPending.u32TimeCounter == 0)) 
	{
		DspUdsTransferData(dspUdsWriteFlashPending.pduRxData, dspUdsWriteFlashPending.pduTxData, dspUdsWriteFlashPending.addrType);
	}
	if( (DCM_WRITE_FLASH_PENDING == dspUdsWriteFlashPending.stateTransferDataExit) && (dspUdsWriteFlashPending.u32TimeCounter == 0)) 
	{
		DspUdsRequestTransferExit(dspUdsWriteFlashPending.pduRxData, dspUdsWriteFlashPending.pduTxData, dspUdsWriteFlashPending.addrType);
	}
}
void DspPendingMainFunction(void) {
	if( DCM_READ_DID_IDLE != dspUdsReadDidPending.state ) {
		DspUdsReadDataByIdentifier(dspUdsReadDidPending.pduRxData, dspUdsReadDidPending.pduTxData);
	}
	if( DCM_WRITE_DID_PENDING == dspUdsWriteDidPending.state ) {
		DspUdsWriteDataByIdentifier(dspUdsWriteDidPending.pduRxData, dspUdsWriteDidPending.pduTxData, dspUdsWriteDidPending.addrType);
	}
	if(dspUdsRoutineDidPending.u32TimeCounter > 0) dspUdsRoutineDidPending.u32TimeCounter--;
	if(( DCM_ROUTINE_DID_PENDING == dspUdsRoutineDidPending.state ) && (dspUdsRoutineDidPending.u32TimeCounter == 0))
	{
		DspUdsRoutineControl(dspUdsRoutineDidPending.pduRxData, dspUdsRoutineDidPending.pduTxData, dspUdsRoutineDidPending.addrType);
	}
}

void DspMain(void)
{
	DspResetMainFunction();
	//DspMemoryMainFunction();
	DspPendingMainFunction();
	DspWriteFlashMainFunction();

#if (DCM_SECURITY_EOL_INDEX != 0)

	for (uint8 i=0; i < DCM_SECURITY_EOL_INDEX; i++)
	{
	    //Check if a wait is required before accepting a request
	   switch (dspUdsSecurityAccesData.secFalseAttemptChk[i].startDelayTimer) {

	       case DELAY_TIMER_ON_EXCEEDING_LIMIT_ACTIVE:
	           TIMER_DECREMENT(dspUdsSecurityAccesData.secFalseAttemptChk[i].timerSecAcssAttempt);
	           if (dspUdsSecurityAccesData.secFalseAttemptChk[i].timerSecAcssAttempt < DCM_MAIN_FUNCTION_PERIOD_TIME_MS) {
	               dspUdsSecurityAccesData.secFalseAttemptChk[i].startDelayTimer = DELAY_TIMER_DEACTIVE;
				   dspUdsSecurityAccesData.secFalseAttemptChk[i].secAcssAttempts = 0;
	           }
	           break;

	       case DELAY_TIMER_DEACTIVE:
	       default:
	           break;
	   }
	}
#endif
}

void DspCancelPendingRequests(void)
{
    if( DCM_READ_DID_IDLE != dspUdsReadDidPending.state ) {
        /* DidRead was in pending state, cancel it */
        DspCancelPendingDid(dspUdsReadDidPending.pendingDid, dspUdsReadDidPending.state, dspUdsReadDidPending.pduTxData);
    }
    dspUdsEcuResetData.resetPending = DCM_DSP_RESET_NO_RESET;
    dspUdsReadDidPending.state = DCM_READ_DID_IDLE;
    dspUdsWriteDidPending.state = DCM_WRITE_DID_IDLE;
	dspUdsRoutineDidPending.state = DCM_ROUTINE_DID_IDLE;
}

boolean DspCheckSessionLevel(Dcm_DspSessionRowType const* const* sessionLevelRefTable)
{
	Std_ReturnType returnStatus;
	boolean levelFound = FALSE;
	Dcm_SesCtrlType currentSession;

	returnStatus = DslGetSesCtrlType(&currentSession);
	if (returnStatus == E_OK) {
	    if( (*sessionLevelRefTable)->Arc_EOL ) {
	        /* No session reference configured, no check should be done. */
	        levelFound = TRUE;
	    } else {
            while ( ((*sessionLevelRefTable)->DspSessionLevel != currentSession) && (!(*sessionLevelRefTable)->Arc_EOL) ) {
                sessionLevelRefTable++;
            }

            if (!(*sessionLevelRefTable)->Arc_EOL) {
                levelFound = TRUE;
            }
	    }
	}

	return levelFound;
}


boolean DspCheckSecurityLevel(Dcm_DspSecurityRowType const* const* securityLevelRefTable)
{
	Std_ReturnType returnStatus;
	boolean levelFound = FALSE;
	Dcm_SecLevelType currentSecurityLevel;

	returnStatus = DslGetSecurityLevel(&currentSecurityLevel);
	if (returnStatus == E_OK) {
	    if( (*securityLevelRefTable)->Arc_EOL ) {
            /* No security level reference configured, no check should be done. */
            levelFound = TRUE;
	    } else {
            while ( ((*securityLevelRefTable)->DspSecurityLevel != currentSecurityLevel) && (!(*securityLevelRefTable)->Arc_EOL) ) {
                securityLevelRefTable++;
            }
            if (!(*securityLevelRefTable)->Arc_EOL) {
                levelFound = TRUE;
            }
	    }
	}

	return levelFound;
}


static Std_ReturnType askApplicationForSessionPermission(Dcm_SesCtrlType newSessionLevel)
{
	Std_ReturnType returnCode = E_OK;
	const Dcm_DslSessionControlType *sesControl = Dcm_ConfigPtr->Dsl->DslSessionControl;
	Dcm_SesCtrlType currentSessionLevel;
	Std_ReturnType result;

	while ( (!sesControl->Arc_EOL) && (returnCode != E_SESSION_NOT_ALLOWED)) {
		if (sesControl->GetSesChgPermission != NULL) {
			result = Dcm_GetSesCtrlType(&currentSessionLevel);
			if (result == E_OK) {
				result = sesControl->GetSesChgPermission(currentSessionLevel ,newSessionLevel);
				if (result != E_OK) {
					returnCode = result;
				}
			} else {
				returnCode = E_NOT_OK;
			}
		}
		sesControl++;
	}

	return returnCode;
}

Dcm_SesCtrlType return_SessionControl(void)
{
	return dspUdsSessionControlData.session;
}

void DspUdsDiagnosticSessionControl(const PduInfoType *pduRxData, PduIdType txPduId, PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType addrType)
{
	const Dcm_DspSessionRowType *sessionRow = Dcm_ConfigPtr->Dsp->DspSession->DspSessionRow;
	Dcm_SesCtrlType reqSessionType;
	Std_ReturnType result;
	Dcm_ProtocolType activeProtocolID;
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	
	if (pduRxData->SduLength == 2) {
		reqSessionType = pduRxData->SduDataPtr[1];
		// Check if type exist in session table
		while ((sessionRow->DspSessionLevel != reqSessionType) && (!sessionRow->Arc_EOL) ) {
			sessionRow++;
		}

		if (!sessionRow->Arc_EOL) {
			result = askApplicationForSessionPermission(reqSessionType);
			if (result == E_OK) {
				DslSetSesCtrlType(reqSessionType);		/** @req DCM311 */

				dspUdsSessionControlData.sessionPending = TRUE;
				dspUdsSessionControlData.session = reqSessionType;
				dspUdsSessionControlData.sessionPduId = txPduId;

				pduTxData->SduDataPtr[1] = reqSessionType;

				if( E_OK == DslGetActiveProtocol(&activeProtocolID) ) {
					// Create positive response
					if( DCM_UDS_ON_CAN == activeProtocolID ) {
						pduTxData->SduDataPtr[2] = (uint8)(sessionRow->DspSessionP2ServerMax >> 8);
						pduTxData->SduDataPtr[3] = (uint8)sessionRow->DspSessionP2ServerMax;
						uint16 p2ServerStarMax10ms = sessionRow->DspSessionP2StarServerMax / 10;
						pduTxData->SduDataPtr[4] = (uint8)(p2ServerStarMax10ms >> 8);
						pduTxData->SduDataPtr[5] = (uint8)p2ServerStarMax10ms;
						pduTxData->SduLength = 6;
					}
					else {
						pduTxData->SduLength = 2;
					}
				}
				else {
					pduTxData->SduLength = 2;
				}
				responseCode = DCM_E_POSITIVERESPONSE;
			}
			else if (result == E_CNC){
				responseCode = DCM_E_CONDITIONSNOTCORRECT;
			}
			else {
				// TODO: Add handling of special case of E_FORCE_RCRRP (Dcm138)
				//DsdDspProcessingDone(DCM_E_CONDITIONSNOTCORRECT);	/** @req DCM308 */
				responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTEDINACTIVESESSION;
			}
		}
		else {
			responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;	/** @req DCM307 */
		}
	}
	else {
		// Wrong length
		responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
	}
	if((addrType == DCM_PROTOCOL_FUNCTIONAL_ADDR_TYPE) && (responseCode!=DCM_E_POSITIVERESPONSE))
	{
		/* ISO14229-1 2020
			In case of functional diagnostics, the NRCs 0x11 (serviceNotSupported), 0x7F (serviceNotSupportedInActiveSession), 
		0x12 (SubFunctionNotSupported), 0x7E (SubFunctionNotSupportedInActiveSession) and 0x31 (requestOutOfRange) will never be 
		returned by the server (exception refers to ISO 14229-1).		
		*/
		for(uint8_t i=0; i<FDNRNRCN; i++)
		{
			if(responseCode == FunctionalDiagnosticsNeverReturnedNegativeResponseCode_Table[i])
			{
				responseCode = DSD_TX_RESPONSE_SUPPRESSED;//不需要返回负响应
				break;
			}
		}
	}
	DsdDspProcessingDone(responseCode);	
}

extern void DcmE_EcuReqReset(void);
void DspUdsEcuReset(const PduInfoType *pduRxData, PduIdType txPduId, PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType addrType)
{
	uint8 reqResetType;
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	
	if (pduRxData->SduLength == 2) {
		reqResetType = pduRxData->SduDataPtr[1];

		switch (reqResetType)
		{
		case DCM_HARD_RESET:
		case DCM_KEY_OFF_ON_RESET:
		case DCM_SOFT_RESET:
			// TODO: Ask application for permission (Dcm373) (Dcm375) (Dcm377)
			DcmE_EcuReqReset();
			dspUdsEcuResetData.resetPduId = txPduId;
			dspUdsEcuResetData.pduTxData = pduTxData;
			dspUdsEcuResetData.resetType = reqResetType;

			switch( DcmE_EcuReset(dspUdsEcuResetData.resetType) )
			{
			case E_OK:
				dspUdsEcuResetData.resetPending = DCM_DSP_RESET_WAIT_TX_CONF;
				// Create positive response
				pduTxData->SduDataPtr[1] = reqResetType;
				pduTxData->SduLength = 2;
				responseCode = DCM_E_POSITIVERESPONSE;
				break;
			case E_PENDING:
				dspUdsEcuResetData.resetPending = DCM_DSP_RESET_PENDING;
				//modity qinminyuan 2022.03.11
				DsdDspProcessingDone(DCM_E_RESPONSEPENDING);
				break;
			case E_NOT_OK:
			default:
				dspUdsEcuResetData.resetPending = DCM_DSP_RESET_NO_RESET;
				DsdDspProcessingDone(DCM_E_CONDITIONSNOTCORRECT);
				break;
			}
			break;

		default:
			responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;
			break;
		}
	}
	else {
		// Wrong length
		responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
	}
	
	if(dspUdsEcuResetData.resetPending != DCM_DSP_RESET_PENDING)
	{

		if((addrType == DCM_PROTOCOL_FUNCTIONAL_ADDR_TYPE) && (responseCode!=DCM_E_POSITIVERESPONSE))
		{
			/* ISO14229-1 2020
				In case of functional diagnostics, the NRCs 0x11 (serviceNotSupported), 0x7F (serviceNotSupportedInActiveSession), 
			0x12 (SubFunctionNotSupported), 0x7E (SubFunctionNotSupportedInActiveSession) and 0x31 (requestOutOfRange) will never be 
			returned by the server (exception refers to ISO 14229-1).		
			*/
			for(uint8_t i=0; i<FDNRNRCN; i++)
			{
				if(responseCode == FunctionalDiagnosticsNeverReturnedNegativeResponseCode_Table[i])
				{
					responseCode = DSD_TX_RESPONSE_SUPPRESSED;//不需要返回负响应
					break;
				}



				
			}
		}
		DsdDspProcessingDone(responseCode);
	}
}

static boolean lookupDid(uint16 didNr, const Dcm_DspDidType **didPtr)
{
	const Dcm_DspDidType *dspDid = Dcm_ConfigPtr->Dsp->DspDid;
	boolean didFound = FALSE;

	while ((dspDid->DspDidIdentifier != didNr) &&  (!dspDid->Arc_EOL)) {
		dspDid++;
	}

	if (!dspDid->Arc_EOL && (!dspDid->DspDidInfoRef->DspDidDynamicllyDefined)) {
		didFound = TRUE;
		*didPtr = dspDid;
	}

	return didFound;
}

static void DspCancelPendingDid(uint16 didNr, ReadDidPendingStateType pendingState, PduInfoType *pduTxData )
{
    const Dcm_DspDidType *didPtr = NULL;
    if( lookupDid(didNr, &didPtr) ) {
        if( DCM_READ_DID_PENDING_COND_CHECK == pendingState ) {
            if( didPtr->DspDidConditionCheckReadFnc != NULL ) {
                (void)didPtr->DspDidConditionCheckReadFnc( pduTxData->SduDataPtr);
            }
        } else if( DCM_READ_DID_PENDING_READ_DATA == pendingState ) {
            if( didPtr->DspDidReadDataFnc != NULL ) {
                if( DATA_PORT_ASYNCH == didPtr->DspDidUsePort ) {
                    (void)didPtr->DspDidReadDataFnc(pduTxData->SduDataPtr);
                }
            }
        } else {
            //ASLOG("DCM", "Not in a pending state\r\n");
        }
    }
}

static Dcm_NegativeResponseCodeType readDidData(const Dcm_DspDidType *didPtr, PduInfoType *pduTxData, uint16*txPos)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;

	if ((didPtr->DspDidInfoRef->DspDidAccess.DspDidRead != NULL) && (didPtr->DspDidConditionCheckReadFnc != NULL) && (didPtr->DspDidReadDataFnc != NULL)) {	/** @req DCM433 */
		if (DspCheckSessionLevel(didPtr->DspDidInfoRef->DspDidAccess.DspDidRead->DspDidReadSessionRef)) { /** @req DCM434 */
			//if (DspCheckSecurityLevel(didPtr->DspDidInfoRef->DspDidAccess.DspDidRead->DspDidReadSecurityLevelRef)) { /** @req DCM435 */
				Std_ReturnType result;
				Dcm_NegativeResponseCodeType errorCode;
				result = didPtr->DspDidConditionCheckReadFnc(&errorCode);
				if ((result == E_OK) && (errorCode == DCM_E_POSITIVERESPONSE)) {	/** @req DCM439 */
					uint16 didLen = 0;
					result = E_NOT_OK;
					if (didPtr->DspDidInfoRef->DspDidFixedLength) {	/** @req DCM436 */
						didLen = didPtr->DspDidSize;
						result = E_OK;
					}
					else {
						if (didPtr->DspDidReadDataLengthFnc != NULL) {
							result = didPtr->DspDidReadDataLengthFnc(&didLen);
						}
					}

					if (result == E_OK) {
						// Now ready for reading the data!
						if ((*txPos + didLen + 2) <= pduTxData->SduLength) {
							pduTxData->SduDataPtr[*txPos] = (didPtr->DspDidIdentifier >> 8) & 0xFFu;
							(*txPos)++;
							pduTxData->SduDataPtr[*txPos] = didPtr->DspDidIdentifier & 0xFFu;
							(*txPos)++;
							result = didPtr->DspDidReadDataFnc(&pduTxData->SduDataPtr[*txPos]);	/** @req DCM437 */
							*txPos += didLen;

							if( E_PENDING == result ) {
								responseCode = DCM_E_RESPONSEPENDING;
							}
							else if (result != E_OK) {
								responseCode = DCM_E_CONDITIONSNOTCORRECT;
							}
						}
						else { // tx buffer full
							responseCode = DCM_E_REQUESTOUTOFRANGE;
						}
					} else if( E_PENDING == result ) {
						responseCode = DCM_E_RESPONSEPENDING;
					} else {	// Not possible to obtain did length
						responseCode = DCM_E_CONDITIONSNOTCORRECT;
					}
				} else if( E_PENDING == result ) {
					responseCode = DCM_E_RESPONSEPENDING;
				} else {	// CheckRead failed
					responseCode = DCM_E_CONDITIONSNOTCORRECT;
				}
			//}
			//else {	// Not allowed in current security level
			//	responseCode = DCM_E_SECURITYACCESSDENIED;
			//}
		}
		else {	// Not allowed in current session
			responseCode = DCM_E_SERVICENOTSUPPORTEDINACTIVESESSION;
		}
	}
	else {	// Read access not configured
		responseCode = DCM_E_REQUESTOUTOFRANGE;
	}
	return responseCode;
}

void DspUdsReadDataByIdentifier(const PduInfoType *pduRxData, PduInfoType *pduTxData)
{
	/** @req DCM253 */
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	Dcm_NegativeResponseCodeType responseCodeOneDid;
	uint16 nrOfDids;
	uint16 didNr;
	const Dcm_DspDidType *didPtr = NULL;
	uint16 txPos = 1;
	uint16 i;
	


	if ( (((pduRxData->SduLength - 1) % 2) == 0) && ( 0 != (pduRxData->SduLength - 1))) {
		nrOfDids = (pduRxData->SduLength - 1) / 2;

		for (i = 0; (i < nrOfDids) && (responseCode == DCM_E_POSITIVERESPONSE || responseCode == DCM_E_RESPONSEPENDING); i++)
		{
			didNr = (uint16)((uint16)pduRxData->SduDataPtr[1 + (i * 2)] << 8) + pduRxData->SduDataPtr[2 + (i * 2)];
			if (lookupDid(didNr, &didPtr)) {	/** @req DCM438 */				
				responseCodeOneDid = readDidData(didPtr, pduTxData, &txPos);
				if( DCM_E_POSITIVERESPONSE != responseCodeOneDid ) {
					/* Only update if response i negative */
					if( (DCM_E_RESPONSEPENDING != responseCodeOneDid) || (DCM_E_POSITIVERESPONSE == responseCode) )
					{
						/* Only update with pending if all previous resp was positive */
						responseCode = responseCodeOneDid;
					}
				}
			}
			else
			{ // DID not found
				responseCode = DCM_E_REQUESTOUTOFRANGE;
			}
		}
	}
	else {
		responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
	}

	if (DCM_E_POSITIVERESPONSE == responseCode) {
		pduTxData->SduLength = txPos;
	}

	if( DCM_E_RESPONSEPENDING == responseCode) {
		dspUdsReadDidPending.state = DCM_READ_DID_PENDING_READ_DATA;
		dspUdsReadDidPending.pduRxData = (PduInfoType*)pduRxData;
		dspUdsReadDidPending.pduTxData = pduTxData;
	}
	else {
		dspUdsReadDidPending.state = DCM_READ_DID_IDLE;
		DsdDspProcessingDone(responseCode);
	}
}

static Dcm_NegativeResponseCodeType writeDidData(const Dcm_DspDidType *didPtr, const PduInfoType *pduRxData, uint16 writeDidLen)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;

	if ((didPtr->DspDidInfoRef->DspDidAccess.DspDidWrite != NULL) && (didPtr->DspDidConditionCheckWriteFnc != NULL) && (didPtr->DspDidWriteDataFnc != NULL)) {	/** @req DCM468 */
		if (DspCheckSessionLevel(didPtr->DspDidInfoRef->DspDidAccess.DspDidWrite->DspDidWriteSessionRef)) { /** @req DCM469 */
			if (DspCheckSecurityLevel(didPtr->DspDidInfoRef->DspDidAccess.DspDidWrite->DspDidWriteSecurityLevelRef)) { /** @req DCM470 */
				Std_ReturnType result;
				Dcm_NegativeResponseCodeType errorCode;
				result = didPtr->DspDidConditionCheckWriteFnc(&errorCode);	/** @req DCM471 */
				if ((result == E_OK) && (errorCode == DCM_E_POSITIVERESPONSE)) {
					uint16 didLen = 0;
					result = E_NOT_OK;
					if (didPtr->DspDidInfoRef->DspDidFixedLength) {	/** @req DCM472 */
						didLen = didPtr->DspDidSize;
						result = E_OK;
					}
					else {
						if (didPtr->DspDidReadDataLengthFnc != NULL) {
							result = didPtr->DspDidReadDataLengthFnc(&didLen);
						}					
					}

					if (result == E_OK) {
						if (didLen == writeDidLen) {	/** @req DCM473 */
							result = didPtr->DspDidWriteDataFnc(&pduRxData->SduDataPtr[3], (uint8)didLen, &responseCode);	/** @req DCM395 */
							if( result != E_OK && responseCode == DCM_E_POSITIVERESPONSE ) {
								responseCode = DCM_E_CONDITIONSNOTCORRECT;
							}
							else if( DCM_E_RESPONSEPENDING == responseCode || E_PENDING == result ) {
								responseCode = DCM_E_RESPONSEPENDING;
							}
						}
						else {
							responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
						}
					}
					else {	// Not possible to obtain did length
						responseCode = DCM_E_CONDITIONSNOTCORRECT;
					}
				}
				else {	// CheckRead failed
					responseCode = DCM_E_CONDITIONSNOTCORRECT;
				}
			}
			else {	// Not allowed in current security level
				responseCode = DCM_E_SECURITYACCESSDENIED;
			}
		}
		else {	// Not allowed in current session
			responseCode = DCM_E_SERVICENOTSUPPORTEDINACTIVESESSION;
		}
	}
	else {	// Read access not configured
		responseCode = DCM_E_REQUESTOUTOFRANGE;
	}

	return responseCode;
}

void DspUdsWriteDataByIdentifier(const PduInfoType *pduRxData, PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType	addrType)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	uint16 didNr = 0;
	const Dcm_DspDidType *didPtr = NULL;

	uint16 didDataLength;
	if(addrType == DCM_PROTOCOL_PHYSICAL_ADDR_TYPE)
	{
		if(pduRxData->SduLength >= 0x03) 
		{
			didDataLength = pduRxData->SduLength - 3;
			didNr = (uint16)((uint16)pduRxData->SduDataPtr[1] << 8) + pduRxData->SduDataPtr[2];
			if (lookupDid(didNr, &didPtr)) 	/** @req DCM467 */
			{
				responseCode = writeDidData(didPtr, pduRxData, didDataLength);
			} 
			else  // DID not found
			{
				responseCode = DCM_E_REQUESTOUTOFRANGE;
			}
		} 
		else 
		{
			responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
		}	
	} 
	else 
	{
		responseCode = DSD_TX_RESPONSE_SUPPRESSED;
	}

	if( DCM_E_RESPONSEPENDING == responseCode ) 
	{
		dspUdsWriteDidPending.state = DCM_WRITE_DID_PENDING;
		dspUdsWriteDidPending.addrType = addrType;
		dspUdsWriteDidPending.pduRxData = pduRxData;
		dspUdsWriteDidPending.pduTxData = pduTxData;
	}
	else	
	{
		if (responseCode == DCM_E_POSITIVERESPONSE) 
		{
			pduTxData->SduLength = 3;
			pduTxData->SduDataPtr[1] = (didNr >> 8) & 0xFFu;
			pduTxData->SduDataPtr[2] = didNr & 0xFFu;
		}

		dspUdsWriteDidPending.state = DCM_WRITE_DID_IDLE;
		DsdDspProcessingDone(responseCode);
	} 
}

boolean SecurityAccessAttempt(uint8 currSecLevIdx, boolean status)
{
	boolean AttCntOverFlag=FALSE;
	
	if(status==TRUE)
	{
		if(dspUdsSecurityAccesData.secFalseAttemptChk[currSecLevIdx].startDelayTimer != DELAY_TIMER_DEACTIVE)
		{
			dspUdsSecurityAccesData.secFalseAttemptChk[currSecLevIdx].secAcssAttempts=0;
			dspUdsSecurityAccesData.secFalseAttemptChk[currSecLevIdx].startDelayTimer = DELAY_TIMER_DEACTIVE;
			dspUdsSecurityAccesData.secFalseAttemptChk[currSecLevIdx].timerSecAcssAttempt=0;
		}
	}
	else
	{
		if (dspUdsSecurityAccesData.secFalseAttemptChk[currSecLevIdx].secAcssAttempts >= dspUdsSecurityAccesData.reqSecLevelRef->DspSecurityNumAttDelay) 
		{							
			//Enable delay timer
			if (Dcm_ConfigPtr->Dsp->DspSecurity->DspSecurityRow[currSecLevIdx].DspSecurityDelayTime >= DCM_MAIN_FUNCTION_PERIOD_TIME_MS) 
			{
				dspUdsSecurityAccesData.secFalseAttemptChk[currSecLevIdx].startDelayTimer = DELAY_TIMER_ON_EXCEEDING_LIMIT_ACTIVE;
				dspUdsSecurityAccesData.secFalseAttemptChk[currSecLevIdx].timerSecAcssAttempt = Dcm_ConfigPtr->Dsp->DspSecurity->DspSecurityRow[currSecLevIdx].DspSecurityDelayTime;
			}
			AttCntOverFlag = TRUE;
		}
		else
		{
			dspUdsSecurityAccesData.secFalseAttemptChk[currSecLevIdx].secAcssAttempts += 1;
		}
	}
	return AttCntOverFlag;
}

Dcm_NegativeResponseCodeType DspUdsSecurityAccessGetSeedSubFnc (const PduInfoType *pduRxData, PduInfoType *pduTxData, Dcm_SecLevelType requestedSecurityLevel) 
{
    Dcm_NegativeResponseCodeType getSeedErrorCode;
    Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
    uint8 cntSecRow = 0;
	boolean isAttCntOverFlag;

    // requestSeed message
    // Check if type exist in security table
    const Dcm_DspSecurityRowType *securityRow = &Dcm_ConfigPtr->Dsp->DspSecurity->DspSecurityRow[0];
    while ((securityRow->DspSecurityLevel != requestedSecurityLevel) && (!securityRow->Arc_EOL)) 
	{
        securityRow++;
        cntSecRow++; // Get the index of the security config
    }
    if (!securityRow->Arc_EOL)
	{
		if(securityRow->GetSeed!=NULL)
		{
			//Check if a wait is required before accepting a request
			dspUdsSecurityAccesData.currSecLevIdx = cntSecRow;
			if (dspUdsSecurityAccesData.secFalseAttemptChk[dspUdsSecurityAccesData.currSecLevIdx].startDelayTimer != DELAY_TIMER_DEACTIVE) 
			{
				responseCode = DCM_E_REQUIREDTIMEDELAYNOTEXPIRED;
			}
			else
			{
				// Check length
				if (pduRxData->SduLength == (2 + securityRow->DspSecurityADRSize)) 
				{ 
					Dcm_SecLevelType activeSecLevel;
					Std_ReturnType result;
					
					result = Dcm_GetSecurityLevel(&activeSecLevel);
					if (result == E_OK) 
					{
						if (requestedSecurityLevel == activeSecLevel) 
						{ 
							pduTxData->SduDataPtr[1] = pduRxData->SduDataPtr[1];
							memset(&pduTxData->SduDataPtr[2], 0, securityRow->DspSecuritySeedSize);
							pduTxData->SduLength = 2 + securityRow->DspSecuritySeedSize;			
							dspUdsSecurityAccesData.reqInProgress = TRUE;
						} 
						else 
						{
							// New security level ask for seed
							Std_ReturnType getSeedResult;
							getSeedResult = securityRow->GetSeed(&pduRxData->SduDataPtr[2], &pduTxData->SduDataPtr[2], &getSeedErrorCode); /** @req DCM324.RequestSeed */
							
							if ((getSeedResult == E_OK) && (getSeedErrorCode == E_OK)) 
							{
								// Everything ok add sub function to tx message and send it.
								pduTxData->SduDataPtr[1] = pduRxData->SduDataPtr[1];
								pduTxData->SduLength = 2 + securityRow->DspSecuritySeedSize;

								dspUdsSecurityAccesData.reqSecLevel = requestedSecurityLevel;
								dspUdsSecurityAccesData.reqSecLevelRef = securityRow;
								dspUdsSecurityAccesData.reqInProgress = TRUE;
							}
							else 
							{
								// GetSeed returned not ok
								responseCode = DCM_E_CONDITIONSNOTCORRECT;
							}
						}
					} 
					else 
					{
						// TODO: What to do?
						responseCode = DCM_E_CONDITIONSNOTCORRECT;//DCM_E_GENERALREJECT;
					}
				}
				else 	// Length not ok
				{
					responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
				}
				if(responseCode != DCM_E_POSITIVERESPONSE)
				{
					isAttCntOverFlag = SecurityAccessAttempt(dspUdsSecurityAccesData.currSecLevIdx, FALSE);
					if(isAttCntOverFlag==TRUE)
					{
						responseCode = DCM_E_REQUIREDTIMEDELAYNOTEXPIRED;
					}				
				}			
			}			
		
		}
		else
		{
			responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTEDINACTIVESESSION;
		}
    }
    else 
	{
        responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;
    }

    return responseCode;
}

// sendKey message
Dcm_NegativeResponseCodeType DspUdsSecurityAccessSendKeySubFnc (const PduInfoType *pduRxData, PduInfoType *pduTxData, Dcm_SecLevelType requestedSecurityLevel) 
{
    Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	const Dcm_DspSecurityRowType *securityRow = &Dcm_ConfigPtr->Dsp->DspSecurity->DspSecurityRow[0];
	boolean isAttCntOverFlag;
	
    while ((securityRow->DspSecurityLevel != requestedSecurityLevel) && (!securityRow->Arc_EOL)) 
	{
        securityRow++;
    }
    if (!securityRow->Arc_EOL) 
	{
		if(securityRow->CompareKey!=NULL)
		{
			if(dspUdsSecurityAccesData.reqInProgress == FALSE)
			{
				dspUdsSecurityAccesData.reqSecLevelRef = securityRow;
			}
			if (pduRxData->SduLength == (2 + dspUdsSecurityAccesData.reqSecLevelRef->DspSecurityKeySize))  /** @req DCM321.SendKey */
			{
				/* Check whether senkey message is sent according to a valid sequence */
				if((dspUdsSecurityAccesData.reqInProgress == TRUE) && (requestedSecurityLevel == dspUdsSecurityAccesData.reqSecLevel))
				{			
					/* Client should reiterate the process of getseed msg, if sendkey fails- ISO14229 */
					dspUdsSecurityAccesData.reqInProgress = FALSE;

					//Check if a wait is required before accepting a request
					if (dspUdsSecurityAccesData.secFalseAttemptChk[dspUdsSecurityAccesData.currSecLevIdx].startDelayTimer != DELAY_TIMER_DEACTIVE) 
					{
						responseCode = DCM_E_EXCEEDNUMBEROFATTEMPTS;//DCM_E_REQUIREDTIMEDELAYNOTEXPIRED;
					}
					else
					{					
						if (dspUdsSecurityAccesData.reqSecLevelRef->CompareKey != NULL) 
						{
							Std_ReturnType compareKeyResult;
							
							compareKeyResult = dspUdsSecurityAccesData.reqSecLevelRef->CompareKey(&pduRxData->SduDataPtr[2]); /** @req DCM324.SendKey */
							if (compareKeyResult == E_OK) 
							{
								// Request accepted
								// Kill timer
								DslSetSecurityLevel(dspUdsSecurityAccesData.reqSecLevelRef->DspSecurityLevel); /** @req DCM325 */
								pduTxData->SduDataPtr[1] = pduRxData->SduDataPtr[1];
								pduTxData->SduLength = 2;							
							}
							else
							{
								responseCode = DCM_E_INVALIDKEY; /** @req DCM660 */
							}
						} 
						else
						{
							responseCode = DCM_E_CONDITIONSNOTCORRECT;
						}
					}
				}
				else 
				{
					responseCode = DCM_E_REQUESTSEQUENCEERROR;	
				}			
			}
			else
			{
				// Length not ok
				responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
			}
			if(responseCode == DCM_E_POSITIVERESPONSE)
			{
				SecurityAccessAttempt(dspUdsSecurityAccesData.currSecLevIdx, TRUE);
			}				
			else
			{
				isAttCntOverFlag = SecurityAccessAttempt(dspUdsSecurityAccesData.currSecLevIdx, FALSE);
				if(isAttCntOverFlag==TRUE)
				{
					responseCode = DCM_E_EXCEEDNUMBEROFATTEMPTS;
				}				
			}							
		
		}
		else
		{
			responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTEDINACTIVESESSION;
		}
	}
	else
	{
		responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;
	}

    return responseCode;
}	

void DspUdsSecurityAccess(const PduInfoType *pduRxData, PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType	addrType)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	
	Dcm_SecLevelType requestedSecurityLevel;
	
	if(addrType == DCM_PROTOCOL_PHYSICAL_ADDR_TYPE)
	{
		if (pduRxData->SduLength >= 0x02) 
		{
			requestedSecurityLevel = (pduRxData->SduDataPtr[1]+1)/2;
			if(pduRxData->SduDataPtr[1] & 0x01u)//seed
			{
				responseCode = DspUdsSecurityAccessGetSeedSubFnc(pduRxData, pduTxData, requestedSecurityLevel);
			}
			else//key
			{
				responseCode = DspUdsSecurityAccessSendKeySubFnc(pduRxData, pduTxData, requestedSecurityLevel);
			}
		}
		else// Length not ok
		{
			responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;	
		}		
	}
	else
	{
		responseCode = DSD_TX_RESPONSE_SUPPRESSED;
	}

	DsdDspProcessingDone(responseCode);

}

void DspUdsTesterPresent(const PduInfoType *pduRxData, PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType addrType)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	
	/** @req DCM251 */
	if (pduRxData->SduLength == 2) {
		switch (pduRxData->SduDataPtr[1])
		{
		case ZERO_SUB_FUNCTION:
			DslResetSessionTimeoutTimer();
			// Create positive response
			pduTxData->SduDataPtr[1] = ZERO_SUB_FUNCTION;
			pduTxData->SduLength = 2;
			responseCode = DCM_E_POSITIVERESPONSE;
			break;

		default:
			responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;
			break;
		}
	}
	else {
		// Wrong length
		responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;		
	}
	

	if((addrType == DCM_PROTOCOL_FUNCTIONAL_ADDR_TYPE) && (responseCode!=DCM_E_POSITIVERESPONSE))
	{
		/* ISO14229-1 2020
			In case of functional diagnostics, the NRCs 0x11 (serviceNotSupported), 0x7F (serviceNotSupportedInActiveSession), 
		0x12 (SubFunctionNotSupported), 0x7E (SubFunctionNotSupportedInActiveSession) and 0x31 (requestOutOfRange) will never be 
		returned by the server (exception refers to ISO 14229-1).		
		*/
		for(uint8_t i=0; i<FDNRNRCN; i++)
		{
			if(responseCode == FunctionalDiagnosticsNeverReturnedNegativeResponseCode_Table[i])
			{
				responseCode = DSD_TX_RESPONSE_SUPPRESSED;//不需要返回负响应
				break;
			}
		}
	}
	DsdDspProcessingDone(responseCode);	
}

void DspUdsControlDtcSetting(const PduInfoType *pduRxData, PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType	addrType)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	if (pduRxData->SduLength == 2) {
		switch (pduRxData->SduDataPtr[1]&0x7f)
		{
		case 0x01:	// ON
		case 0x02:	// OFF
			{
				pduTxData->SduDataPtr[1] = pduRxData->SduDataPtr[1];
				pduTxData->SduLength = 2;
				responseCode = DCM_E_POSITIVERESPONSE;
			}
			break;

		default:
			responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;
			break;
		}
	}
	else {
		// Wrong length
		responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
	}
	if((addrType == DCM_PROTOCOL_FUNCTIONAL_ADDR_TYPE) && (responseCode!=DCM_E_POSITIVERESPONSE))
	{
		/* ISO14229-1 2020
			In case of functional diagnostics, the NRCs 0x11 (serviceNotSupported), 0x7F (serviceNotSupportedInActiveSession), 
		0x12 (SubFunctionNotSupported), 0x7E (SubFunctionNotSupportedInActiveSession) and 0x31 (requestOutOfRange) will never be 
		returned by the server (exception refers to ISO 14229-1).		
		*/
		for(uint8_t i=0; i<FDNRNRCN; i++)
		{
			if(responseCode == FunctionalDiagnosticsNeverReturnedNegativeResponseCode_Table[i])
			{
				responseCode = DSD_TX_RESPONSE_SUPPRESSED;//不需要返回负响应
				break;
			}
		}
	}
	DsdDspProcessingDone(responseCode);
}

void DspDcmConfirmation(PduIdType confirmPduId)
{
	DslResetSessionTimeoutTimer(); /** @req DCM141 */
	if ( DCM_DSP_RESET_WAIT_TX_CONF == dspUdsEcuResetData.resetPending ) {
		if (confirmPduId == dspUdsEcuResetData.resetPduId) {
			dspUdsEcuResetData.resetPending = DCM_DSP_RESET_NO_RESET;
			DcmE_EcuPerformReset(dspUdsEcuResetData.resetType);
		}
	}

	if (dspUdsSessionControlData.sessionPending) {
		if (confirmPduId == dspUdsSessionControlData.sessionPduId) {
			dspUdsSessionControlData.sessionPending = FALSE;
			Dcm_DiagnosticSessionControl(dspUdsSessionControlData.session);
		}
	}
}
#ifdef DCM_USE_SERVICE_INPUT_OUTPUT_CONTROL_BY_IDENTIFIER
static const Dcm_DspDidControlRecordSizesType* getControlRecordSizesForControlParameter(uint8 controlParam, const Dcm_DspDidControlType *DidControl)
{
	switch( controlParam )
	{
	case DCM_RETURN_CONTROL_TO_ECU:
		return DidControl->DspDidReturnControlToEcu;
	case DCM_RESET_TO_DEFAULT:
		return DidControl->DspDidResetToDefault;
	case DCM_FREEZE_CURRENT_STATE:
		return DidControl->DspDidFreezeCurrentState;
	case DCM_SHORT_TERM_ADJUSTMENT:
		return DidControl->DspDidShortTermAdjustment;
	default:
		return NULL;
	}
}
static void DspStopInputOutputControl(boolean checkSessionAndSecLevel)
{
    const Dcm_DspDidControlType *DidControl = NULL;
    const Dcm_DspDidType *DidPtr = NULL;
    Dcm_NegativeResponseCodeType responseCode;
    /* @req DCM628 */
    for(uint16 i = 0; i < DCM_DID_LIST_EOL_INDEX; i++) 
	{
        if( IOControlStateList[i].controlActive ) 
		{
            /* Control not in the hands of the ECU.Return it. */
            if(lookupDid(IOControlStateList[i].did, &DidPtr)) 
			{
                DidControl = DidPtr->DspDidInfoRef->DspDidAccess.DspDidControl;
                if(NULL != DidControl) 
				{
                    boolean returnToECU = TRUE;
                    if(checkSessionAndSecLevel) 
					{
                        /* Should check if supported in session and security level */
                        if( DspCheckSessionLevel(DidControl->DspDidControlSessionRef) 
							&& DspCheckSecurityLevel(DidControl->DspDidControlSecurityLevelRef) ) 
						{
                            /* Control is supported in current session and security level.
                             * Do not return control to ECU. */
                            returnToECU = FALSE;
                        }
                    }
                    if( returnToECU ) 
					{
                        /* Return control to the ECU */
                        if(DidPtr->DspDidReturnControlToEcuFnc != NULL) 
						{
                            (void)DidPtr->DspDidReturnControlToEcuFnc(DCM_INITIAL, &responseCode);
                        }
                        IOControlStateList[i].controlActive = FALSE;
                    } else {
                        /* Control is supported in the current session and security level */
                    }
                } 
				else 
				{
                    /* No control access. */
                    IOControlStateList[i].controlActive = FALSE;
                }
            } 
			else 
			{
                /* Did not found in config. Strange.. */
                IOControlStateList[i].controlActive = FALSE;
            }
        }
    }
}

static void DspIOControlSetActive(uint16 didNr, boolean active)
{
    boolean done = FALSE;
    if( active ) 
	{
        /* Check if did already in list */
        for(uint16 i = 0; (i < DCM_DID_LIST_EOL_INDEX) && !done; i++) 
		{
            if(didNr == IOControlStateList[i].did) 
			{
                IOControlStateList[i].controlActive = TRUE;
                done = TRUE;
            }
        }
        if( !done ) 
		{
            /* Was not in list. Find an unused slot */
            for(uint16 i = 0; (i < DCM_DID_LIST_EOL_INDEX) && !done; i++) 
			{
                if( !IOControlStateList[i].controlActive ) 
				{
                    IOControlStateList[i].did = didNr;
                    IOControlStateList[i].controlActive = TRUE;
                    done = TRUE;
                }
            }
        }
    } 
	else 
	{
        for(uint16 i = 0; (i < DCM_DID_LIST_EOL_INDEX) && !done; i++) 
		{
            if( didNr == IOControlStateList[i].did ) 
			{
                IOControlStateList[i].controlActive = FALSE;
                done = TRUE;
            }
        }
    }
    if( active && !done ) {
        /* Should set control active but could not find an entry
         * to use. */
		//ASLOG("DCM", "DCM_E_UNEXPECTED_EXECUTION\r\n");
    }
}
/* This is used when the port is not USE_ECU_SIGNAL */
static Std_ReturnType FunctionInputOutputControl(const Dcm_DspDidType *DidPtr, Dcm_IOControlParameterType action, uint8* controlOptionRecord, Dcm_NegativeResponseCodeType* responseCode) {

    *responseCode = DCM_E_REQUESTOUTOFRANGE; // Value to use if no callback found
    Std_ReturnType retVal = E_NOT_OK;

    switch(action)
    {
    case DCM_RETURN_CONTROL_TO_ECU:
        if(DidPtr->DspDidReturnControlToEcuFnc != NULL)
        {
            retVal = DidPtr->DspDidReturnControlToEcuFnc(DCM_INITIAL ,responseCode);
        }
        break;
    case DCM_RESET_TO_DEFAULT:
        if(DidPtr->DspDidResetToDefaultFnc != NULL)
        {
            retVal = DidPtr->DspDidResetToDefaultFnc(DCM_INITIAL ,responseCode);
        }
        break;
    case DCM_FREEZE_CURRENT_STATE:
        if(DidPtr->DspDidFreezeCurrentStateFnc != NULL)
        {
            retVal = DidPtr->DspDidFreezeCurrentStateFnc(DCM_INITIAL ,responseCode);
        }
        break;
    case DCM_SHORT_TERM_ADJUSTMENT:
        if(DidPtr->DspDidShortTermAdjustmentFnc != NULL)
        {
            retVal = DidPtr->DspDidShortTermAdjustmentFnc(controlOptionRecord, DCM_INITIAL, responseCode);
        }
        break;
    default:
        break;
    }

    return retVal;
}


void DspIOControlByDataIdentifier(const PduInfoType *pduRxData,PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType	addrType)
{
	uint16 didNr;
	uint8 controlStatusRecordSize = 0;
	Std_ReturnType retVal = E_OK;
	const Dcm_DspDidType *DidPtr = NULL;
	const Dcm_DspDidControlType *DidControl = NULL;
	const Dcm_DspDidControlRecordSizesType* controlRecordSizes = NULL;
	Dcm_NegativeResponseCodeType responseCode = DCM_E_REQUESTOUTOFRANGE;

	if(addrType == DCM_PROTOCOL_PHYSICAL_ADDR_TYPE)
	{
		if(pduRxData->SduLength >= SID_LEN + IOI_LEN + IOCP_LEN)
		{
			didNr = (pduRxData->SduDataPtr[IOI_INDEX] << 8 & DCM_DID_HIGH_MASK) + (pduRxData->SduDataPtr[IOI_INDEX+1] & DCM_DID_LOW_MASK);
			if(TRUE == lookupDid(didNr, &DidPtr))
			{
				DidControl = DidPtr->DspDidInfoRef->DspDidAccess.DspDidControl;
				if(NULL != DidControl)
				{
					if(TRUE == DspCheckSessionLevel(DidControl->DspDidControlSessionRef))
					{
						if(TRUE == DspCheckSecurityLevel(DidControl->DspDidControlSecurityLevelRef))
						{
							controlRecordSizes = getControlRecordSizesForControlParameter(pduRxData->SduDataPtr[IOCP_INDEX], DidControl);
							if( controlRecordSizes != NULL )
							{
	                            uint8 *maskPtr = NULL;
								maskPtr = maskPtr;
	                            boolean requestOk = FALSE;
	                            controlStatusRecordSize = controlRecordSizes->DspDidControlStatusRecordSize;
	                            if( pduRxData->SduLength == SID_LEN + IOI_LEN + IOCP_LEN + controlRecordSizes->DspDidControlOptionRecordSize ) {
	                                maskPtr = NULL;
	                                requestOk = TRUE;
	                            } else if( pduRxData->SduLength == SID_LEN + IOI_LEN + IOCP_LEN + controlRecordSizes->DspDidControlOptionRecordSize + controlRecordSizes->DspDidControlEnableMaskRecordSize) {
	                                maskPtr = &pduRxData->SduDataPtr[COR_INDEX + controlRecordSizes->DspDidControlOptionRecordSize];
	                                requestOk = TRUE;
	                            }
															
	                            if( requestOk) {
	                                retVal = FunctionInputOutputControl(DidPtr, pduRxData->SduDataPtr[IOCP_INDEX], &pduRxData->SduDataPtr[COR_INDEX], &responseCode);
#ifdef DCM_USE_CONTROL_DIDS
	                                if( (E_OK == retVal) && (DCM_E_POSITIVERESPONSE == responseCode) ) {
	                                    switch(pduRxData->SduDataPtr[IOCP_INDEX])
	                                    {
	                                    case DCM_RETURN_CONTROL_TO_ECU:
	                                        DspIOControlSetActive(didNr, FALSE);
	                                        break;
	                                    case DCM_RESET_TO_DEFAULT:
	                                    case DCM_FREEZE_CURRENT_STATE:
	                                    case DCM_SHORT_TERM_ADJUSTMENT:
	                                        DspIOControlSetActive(didNr, TRUE);
	                                        break;
	                                    default:
	                                        break;
	                                    }
	                                }
#endif
	                            } else {
	                                responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
	                            }
	                            if(responseCode == DCM_E_POSITIVERESPONSE && retVal != E_OK) {
	                                responseCode = DCM_E_CONDITIONSNOTCORRECT;
	                            }
	                        }
							else
							{
								responseCode = DCM_E_REQUESTOUTOFRANGE;
							}
						}
						else
						{
							responseCode = DCM_E_SECURITYACCESSDENIED;
						}
					}
					else
					{
						responseCode = DCM_E_SERVICENOTSUPPORTEDINACTIVESESSION;
					}
				}
				else
				{
					responseCode = DCM_E_REQUESTOUTOFRANGE;
				}
			}
			else
			{
				responseCode = DCM_E_REQUESTOUTOFRANGE;
			}
		}
		else
		{
			responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
		}
		if(responseCode == DCM_E_POSITIVERESPONSE)
		{
	        if( pduTxData->SduLength >= SID_LEN + IOI_LEN + IOCP_LEN + controlStatusRecordSize ) {
	            pduTxData->SduLength = SID_LEN + IOI_LEN + IOCP_LEN + controlStatusRecordSize;
	            pduTxData->SduDataPtr[1] = pduRxData->SduDataPtr[1];
	            pduTxData->SduDataPtr[2] = pduRxData->SduDataPtr[2];
	            pduTxData->SduDataPtr[3] = pduRxData->SduDataPtr[IOCP_INDEX];
	            if((NULL != DidPtr) && (DidPtr->DspDidReadDataFnc != NULL)) {
	                if( (DATA_PORT_SYNCH == DidPtr->DspDidUsePort) || (DATA_PORT_ECU_SIGNAL == DidPtr->DspDidUsePort) ) {
	                    if( E_OK != DidPtr->DspDidReadDataFnc(&pduTxData->SduDataPtr[4])) {
	                        retVal = E_NOT_OK;
	                    }
	                } else if(DATA_PORT_ASYNCH == DidPtr->DspDidUsePort) {
	                    retVal = DidPtr->DspDidReadDataFnc( &pduTxData->SduDataPtr[4]);
	                } else {
	                    retVal = E_NOT_OK;
	                }
	                if(E_OK != retVal) {
	                    responseCode = DCM_E_CONDITIONSNOTCORRECT;
	                }
	            } else {
	                responseCode = DCM_E_REQUESTOUTOFRANGE;
	            }
	        } else {
	            responseCode = DCM_E_REQUESTOUTOFRANGE;
	        }
	    }
	}
	else
	{
		responseCode = DSD_TX_RESPONSE_SUPPRESSED;;
	}
	DsdDspProcessingDone(responseCode);
}
#endif

void DspCommunicationControl(const PduInfoType *pduRxData,PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType addrType)
{
    Dcm_NegativeResponseCodeType responseCode = DCM_E_REQUESTOUTOFRANGE;
    uint8 subFunction = (pduRxData->SduDataPtr[SF_INDEX]&0x7F);
    
    if(pduRxData->SduLength == 3) {
        if( !IS_ISO_RESERVED(subFunction) ) {
            Dcm_E_CommunicationControl(subFunction, pduRxData->SduDataPtr[CC_CTP_INDEX], &responseCode);
            if( !((DCM_E_POSITIVERESPONSE == responseCode) ||
                    (DCM_E_REQUESTOUTOFRANGE == responseCode) ||
                    (DCM_E_CONDITIONSNOTCORRECT == responseCode) ||
                    (DCM_E_SUBFUNCTIONNOTSUPPORTED == responseCode)) ) {
				//ASLOG("DCM", "[Dcm_Dsp]DCM_UDS_COMMUNICATION_CONTROL_ID:%d\r\r",responseCode);
                responseCode = DCM_E_REQUESTOUTOFRANGE;
            } else {
                /* Valid response. */
            }
        } else {
            /* ISO reserved for future definition */
            responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;
        }
    } else {
        /* Length not correct */
        responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
    }

    if(responseCode == DCM_E_POSITIVERESPONSE)
    {
        pduTxData->SduLength = SID_LEN + SF_LEN;
        pduTxData->SduDataPtr[SF_INDEX] = pduRxData->SduDataPtr[SF_INDEX];
    }
	if((addrType == DCM_PROTOCOL_FUNCTIONAL_ADDR_TYPE) && (responseCode!=DCM_E_POSITIVERESPONSE))
	{
		/* ISO14229-1 2020
			In case of functional diagnostics, the NRCs 0x11 (serviceNotSupported), 0x7F (serviceNotSupportedInActiveSession), 
		0x12 (SubFunctionNotSupported), 0x7E (SubFunctionNotSupportedInActiveSession) and 0x31 (requestOutOfRange) will never be 
		returned by the server (exception refers to ISO 14229-1).		
		*/
		for(uint8_t i=0; i<FDNRNRCN; i++)
		{
			if(responseCode == FunctionalDiagnosticsNeverReturnedNegativeResponseCode_Table[i])
			{
				responseCode = DSD_TX_RESPONSE_SUPPRESSED;//不需要返回负响应
				break;
			}
		}
	}
	DsdDspProcessingDone(responseCode);
}



/********************$31 *****/
static boolean lookupRoutine(uint16 routineId, const Dcm_DspRoutineType **routinePtr)
{
	const Dcm_DspRoutineType *dspRoutine = Dcm_ConfigPtr->Dsp->DspRoutine;
	boolean routineFound = FALSE;

	while ((dspRoutine->DspRoutineIdentifier != routineId) &&  (!dspRoutine->Arc_EOL)) {
		dspRoutine++;
	}

	if (!dspRoutine->Arc_EOL) {
		routineFound = TRUE;
		*routinePtr = dspRoutine;
	}

	return routineFound;
}

static Dcm_NegativeResponseCodeType requestRoutineResults(const Dcm_DspRoutineType *routinePtr, PduInfoType *pduTxData)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	Std_ReturnType routineResult;

	if(routinePtr->DspRoutineInfoRef->DspRoutineRequestRes!=NULL)
	{
		if ((routinePtr->DspRoutineInfoRef->DspRoutineRequestRes->DspReqResRtnCtrlOptRecSize + 4) <= pduTxData->SduLength) {
			uint16 currentDataLength = 0;
			routineResult = routinePtr->DspRequestResultRoutineFnc(&pduTxData->SduDataPtr[4], &responseCode);	/** @req DCM404 */ /** @req DCM405 */
			// pduTxData->SduLength = currentDataLength + 5;/*   4---- 5 */
			if (routineResult != E_OK && responseCode == DCM_E_POSITIVERESPONSE) {
				responseCode = DCM_E_CONDITIONSNOTCORRECT;
			}
			// if(responseCode == DCM_E_POSITIVERESPONSE && pduTxData->SduLength > routinePtr->DspRoutineInfoRef->DspRoutineRequestRes->DspReqResRtnCtrlOptRecSize + 4) 
			if(responseCode == DCM_E_POSITIVERESPONSE) 
			{
			    pduTxData->SduLength = routinePtr->DspRoutineInfoRef->DspRoutineRequestRes->DspReqResRtnCtrlOptRecSize + 4;
			}
		}
		else {
			responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
		}	
	}
	else
	{
		responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;
	}

    return responseCode;
	
}

static Dcm_NegativeResponseCodeType startRoutine(const Dcm_DspRoutineType *routinePtr, const PduInfoType *pduRxData, PduInfoType *pduTxData)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	Std_ReturnType routineResult;

	if(routinePtr->DspRoutineInfoRef->DspStartRoutine!=NULL)
	{
		if ((routinePtr->DspRoutineInfoRef->DspStartRoutine->DspStartRoutineCtrlOptRecSize + 4) == pduRxData->SduLength) 
		{
			//uint16 currentDataLength = pduRxData->SduLength - 4;
			routineResult = routinePtr->DspStartRoutineFnc(&pduRxData->SduDataPtr[4], &pduTxData->SduDataPtr[4], &responseCode);	/** @req DCM400 */ /** @req DCM401 */
			// pduTxData->SduLength = 5;//currentDataLength + 5;
			if (routineResult != E_OK && responseCode == DCM_E_POSITIVERESPONSE) {
				responseCode = DCM_E_CONDITIONSNOTCORRECT;
			}
			// if(responseCode == DCM_E_POSITIVERESPONSE && pduTxData->SduLength > routinePtr->DspRoutineInfoRef->DspStartRoutine->DspStartRoutineStsOptRecSize + 4) 
			if(responseCode == DCM_E_POSITIVERESPONSE) 
			{
			    pduTxData->SduLength = routinePtr->DspRoutineInfoRef->DspStartRoutine->DspStartRoutineStsOptRecSize + 4;
			}
		}
		else {
			responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
		}	
	}
	else
	{
		responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;
	}
	return responseCode;
}

static Dcm_NegativeResponseCodeType stopRoutine(const Dcm_DspRoutineType *routinePtr, const PduInfoType *pduRxData, PduInfoType *pduTxData)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	Std_ReturnType routineResult;

	if(routinePtr->DspRoutineInfoRef->DspRoutineStop!=NULL)
	{
		if ((routinePtr->DspRoutineInfoRef->DspRoutineStop->DspStopRoutineStsOptRecSize + 4) == pduTxData->SduLength) 
		{
			//uint16 currentDataLength = pduRxData->SduLength - 4;
			routineResult = routinePtr->DspStopRoutineFnc(&pduRxData->SduDataPtr[4], &pduTxData->SduDataPtr[4], &responseCode);	/** @req DCM400 */ /** @req DCM401 */
			// pduTxData->SduLength = 5;//currentDataLength + 5;
			if (routineResult != E_OK && responseCode == DCM_E_POSITIVERESPONSE) {
				responseCode = DCM_E_CONDITIONSNOTCORRECT;
			}
			// if(responseCode == DCM_E_POSITIVERESPONSE && pduTxData->SduLength > routinePtr->DspRoutineInfoRef->DspRoutineStop->DspStopRoutineStsOptRecSize + 4) 
			if(responseCode == DCM_E_POSITIVERESPONSE) 
			{
			    pduTxData->SduLength = routinePtr->DspRoutineInfoRef->DspRoutineStop->DspStopRoutineStsOptRecSize + 4;
			}
		}
		else {
			responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
		}	
	}
	else
	{
		responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;
	}
	return responseCode;
}

void DspUdsRoutineControl(const PduInfoType *pduRxData, PduInfoType *pduTxData, Dcm_ProtocolAddrTypeType	addrType)
{
	/** @req DCM257 */
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	uint8 subFunctionNumber = 0;
	uint16 routineId = 0;
	const Dcm_DspRoutineType *routinePtr = NULL;
	
	if(addrType == DCM_PROTOCOL_PHYSICAL_ADDR_TYPE)
	{
		if (pduRxData->SduLength >= 4) {
			subFunctionNumber = pduRxData->SduDataPtr[1];
			routineId = (uint16)((uint16)pduRxData->SduDataPtr[2] << 8) + pduRxData->SduDataPtr[3];
			if (lookupRoutine(routineId, &routinePtr)) 
			{
				if (DspCheckSecurityLevel(&routinePtr->DspRoutineInfoRef->DspRoutineAuthorization.DspRoutineSecurityLevelRef[0])) 
				{
					switch (subFunctionNumber) {
					case 0x01:	// startRoutine
						responseCode = startRoutine(routinePtr, pduRxData, pduTxData);					
						break;

					case 0x03:	// requestRoutineResults
						responseCode =  requestRoutineResults(routinePtr, pduTxData);
						break;

					default:	// This shall never happen
						responseCode = DCM_E_SUBFUNCTIONNOTSUPPORTED;
						break;
					}					
				}
				else
				{
					responseCode = DCM_E_SECURITYACCESSDENIED;
				}
			}
			else {	// Unknown routine identifier
				responseCode = DCM_E_REQUESTOUTOFRANGE;
			}
		}
		else {
			// Wrong length
			responseCode = DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT;
		}
	}
	else
	{
		responseCode = DCM_E_SERVICENOTSUPPORTEDINACTIVESESSION;
	}
	if (DCM_E_RESPONSEPENDING != responseCode) {
		// Add header to the positive response message
		pduTxData->SduDataPtr[1] = subFunctionNumber;
		pduTxData->SduDataPtr[2] = (routineId >> 8) & 0xFFu;
		pduTxData->SduDataPtr[3] = routineId & 0xFFu;	
		dspUdsRoutineDidPending.state= DCM_ROUTINE_DID_IDLE;
		DsdDspProcessingDone(responseCode);
	}
	else
	{
		dspUdsRoutineDidPending.state= DCM_ROUTINE_DID_PENDING;
		dspUdsRoutineDidPending.addrType = addrType;
		dspUdsRoutineDidPending.pduRxData = pduRxData;
		dspUdsRoutineDidPending.pduTxData = pduTxData;
		dspUdsRoutineDidPending.u32TimeCounter = 10;
	}
}
extern void requestDownload(const PduInfoType *pduRxData, PduInfoType *pduTxData,Dcm_NegativeResponseCodeType *errorCode);
void DspUdsRequestDownload(const PduInfoType *pduRxData, PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType addrType)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	(void)pduRxData;
	if(addrType == DCM_PROTOCOL_PHYSICAL_ADDR_TYPE)
	{
		requestDownload(pduRxData, pduTxData, &responseCode);
	}
	else
	{
		responseCode = DCM_E_SERVICENOTSUPPORTEDINACTIVESESSION;
	}
    DsdDspProcessingDone(responseCode);
}
extern void transferData(const PduInfoType *pduRxData, PduInfoType *pduTxData, Dcm_NegativeResponseCodeType *errorCode);
void DspUdsTransferData(const PduInfoType *pduRxData, PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType addrType)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	if(addrType == DCM_PROTOCOL_PHYSICAL_ADDR_TYPE)
	{
		transferData(pduRxData, pduTxData, &responseCode);
	}
	else
	{
		responseCode = DCM_E_SERVICENOTSUPPORTEDINACTIVESESSION;
	}

	if( DCM_E_RESPONSEPENDING != responseCode ) {
		if (responseCode == DCM_E_POSITIVERESPONSE) {
			pduTxData->SduLength = 2;
			pduTxData->SduDataPtr[1]=pduRxData->SduDataPtr[1];
		}
		dspUdsWriteFlashPending.stateTransferData= DCM_WRITE_FLASH_IDLE;
		DsdDspProcessingDone(responseCode);
	}
	else {
		dspUdsWriteFlashPending.u32TimeCounter = 14;
		dspUdsWriteFlashPending.stateTransferData= DCM_WRITE_FLASH_PENDING;
		dspUdsWriteFlashPending.addrType = addrType;
		dspUdsWriteFlashPending.pduRxData = pduRxData;
		dspUdsWriteFlashPending.pduTxData = pduTxData;
	}
}
extern void requestTransferExit(const PduInfoType *pduRxData, PduInfoType *pduTxData,Dcm_NegativeResponseCodeType *errorCode);
void DspUdsRequestTransferExit(const PduInfoType *pduRxData, PduInfoType *pduTxData,Dcm_ProtocolAddrTypeType addrType)
{
	Dcm_NegativeResponseCodeType responseCode = DCM_E_POSITIVERESPONSE;
	(void)pduRxData;
	if(addrType == DCM_PROTOCOL_PHYSICAL_ADDR_TYPE)
	{
	    requestTransferExit(pduRxData, pduTxData,  &responseCode);    //transferResponseParameterRecore, user-defined
	}
	else
	{
		responseCode = DCM_E_SERVICENOTSUPPORTEDINACTIVESESSION;
	}

	if( DCM_E_RESPONSEPENDING != responseCode ) {
		dspUdsWriteFlashPending.stateTransferDataExit= DCM_WRITE_FLASH_IDLE;
		DsdDspProcessingDone(responseCode);
	}
	else {
		dspUdsWriteFlashPending.u32TimeCounter = 10;
		dspUdsWriteFlashPending.stateTransferDataExit= DCM_WRITE_FLASH_PENDING;
		dspUdsWriteFlashPending.addrType = addrType;
		dspUdsWriteFlashPending.pduRxData = pduRxData;
		dspUdsWriteFlashPending.pduTxData = pduTxData;
	}
    
}




